package com.ecarx.camera.ui.camera;

import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.ecarx.camera.R;
import com.ecarx.camera.constant.Constants;
import com.ecarx.camera.ui.BaseFragment;
import com.ecarx.camera.ui.camera.dvr.DvrCameraUI;
import com.ecarx.camera.ui.contract.IMainView;
import com.ecarx.camera.utils.LogUtils;
import com.ecarx.camera.worker.camera.ICameraViewWorker;
import com.ecarx.camera.worker.camera.ICameraWorker;
import com.ecarx.camera.worker.camera.back.BackCameraViewWorker;
import com.ecarx.camera.worker.camera.dvr.DvrCameraWorker;
import com.ecarx.camera.worker.camera.interior.InteriorCameraViewWorker;
import com.ecarx.camera.worker.location.XCLocationManager;
import com.otaliastudios.cameraview.CameraView;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.preview.CameraPreview;

public class CameraFragment extends BaseFragment implements CameraPreview.DisposableFrameCallback{

    private ICameraUI mCurCameraUI;
    private ICameraWorker mCurCameraWorker;

    private final ICameraUI mCameraDvrUI = new DvrCameraUI();
    private final ICameraWorker mCameraDvrWorker = Constants.USE_BACK_CAMERA2_TO_REPLACE_DVR ? new BackCameraViewWorker() : new DvrCameraWorker();

    private CameraView mCameraPreviewView;
    private View loading_view;
    private ProgressBar progressBar;
    private TextView loadingTv;
    private @Constants.FacingType int mFacingType;

    public CameraFragment() {
    }

    @Override
    protected int getLayoutResId() {
        return R.layout.fragment_camera;
    }

    @Override
    protected void initData() {
        super.initData();
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void bindViews() {
        super.bindViews();
        mCameraPreviewView = view.findViewById(R.id.camera_view);
        loading_view = view.findViewById(R.id.loading_view);
        loadingTv = view.findViewById(R.id.loading_tv);
        progressBar = view.findViewById(R.id.loading_progress);

        mCameraPreviewView.setLifecycleOwner(getActivity());
        mCameraPreviewView.setDisposableFrameCallback(this);
        bindDvr();
        if (mCurCameraUI != null) {
            mCurCameraUI.showAll(true);
        }
        updateCameraPreviewFacing();
    }

    private void bindDvr() {
        mCameraDvrWorker.init();
        mCameraDvrUI.init((IMainView) getParentFragment(), this);
        mCameraDvrUI.bindViews(view.findViewById(R.id.camera_dvr_ui));
        mCameraDvrUI.bindWorker(mCurCameraWorker);
        if (mCameraDvrWorker instanceof ICameraViewWorker) {
            ((ICameraViewWorker)mCameraDvrWorker).setCameraView(mCameraPreviewView);
        }
        mCameraDvrWorker.bindUI(mCurCameraUI);
    }

    @Override
    protected void initViews() {
        super.initViews();
        if (mCurCameraUI != null) {
            mCameraDvrUI.updateViewsWhenConfigureChanged();
        }
    }

    @Override
    protected void onResume(boolean firstResume) {
        super.onResume(firstResume);
        if (mCurCameraWorker != null) {
            mCurCameraWorker.doOnResume();
        }
        //切换相机需要时间，添加遮罩，防止用户看到上一帧黑屏或错误画面
        showLoadingView();
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mCurCameraWorker != null) {
            mCurCameraWorker.doOnPause();
        }
        showLoadingViewOnPause();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LogUtils.d(TAG, "Lifecycle-> onCreate, this:" + this );
        XCLocationManager.get().initLocationListener();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        LogUtils.d(TAG, "Lifecycle-> onDestroy, this:" + this);
        if(disposableFrameHandler != null){
            disposableFrameHandler.removeCallbacksAndMessages(null);
        }
        mCameraDvrWorker.doOnDestroy();
        XCLocationManager.get().removeListener();
        if (mCameraPreviewView != null) {
            mCameraPreviewView.setLifecycleOwner(null);
            mCameraPreviewView = null;
        }
        mCameraDvrUI.init(null, null);
    }

    private String enableDisposableFrameKey = "";
    private void showLoadingView(){
        LogUtils.i(TAG, " showLoadingView");
        if(mCameraPreviewView != null){
            progressAnimation(false);
            enableDisposableFrameKey = String.valueOf(System.currentTimeMillis());
            sendDisposableFrame(enableDisposableFrameKey);
        }
    }

    private void showLoadingViewOnPause() {
        loading_view.setVisibility(View.VISIBLE);
    }

    private void sendDisposableFrame(String key){
        LogUtils.i(TAG ," removeCallbacksAndMessages & sendMessageDelayed");
        disposableFrameHandler.removeCallbacksAndMessages(null);
        Message msg = new Message();
        msg.what = WHAT_DISPOSABLE_FRAME;
        msg.obj = key;
        //此处500ms是测试下来得出最佳值，若在极端情况下，可能出现loading无法遮住错误的画面提前消失，除非继续加大延迟时间
        disposableFrameHandler.sendMessageDelayed(msg, 500);
    }

    private static final int WHAT_DISPOSABLE_FRAME = 10;
    private final Handler disposableFrameHandler = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            if(msg.what == WHAT_DISPOSABLE_FRAME){
                if(mCameraPreviewView != null){
                    loading_view.setVisibility(View.VISIBLE);
                    LogUtils.i(TAG ," Delayed 500ms execDisposableFrameCallback ");
                    mCameraPreviewView.execDisposableFrameCallback((String)msg.obj);
                }
            }
        }
    };

    /**
     * @param finisAnimation  true 展示中间状态 false 隐藏中间状态
     * */
    private void progressAnimation(boolean finisAnimation) {
        if (loading_view != null) {
            boolean faceType = mFacingType == Constants.FacingType.EXTERIOR;
            int id;
            if (faceType) {
                id = R.string.camera_loading_exterior;
            } else {
                id = R.string.camera_loading_interior;
            }
            loadingTv.setText(getResources().getText(id));
            if (finisAnimation) {
                //准备关闭中间状态
                if (loading_view.getVisibility() != View.GONE) {
                    ValueAnimator fadeInAnimation = ValueAnimator.ofInt(11, 100);
                    fadeInAnimation.setDuration(500);
                    fadeInAnimation.addUpdateListener(animation -> {
                        // 在动画更新时调用，获取当前透明度值
                        int alphaValue = (int) animation.getAnimatedValue();
                        progressBar.setProgress(alphaValue);
                        LogUtils.e(TAG, " Delayed alphaValue = " + alphaValue);
                        if (alphaValue >= 100) {
                            loading_view.setVisibility(View.GONE);
                            progressBar.setProgress(10);
                        }
                    });
                    // 启动动画
                    fadeInAnimation.start();
                }
            } else {
                //显示 中间状态
                loading_view.setVisibility(View.VISIBLE);
                progressBar.setProgress(10);
            }
        }

    }

    @Override
    public void onFrameAvailable(String key, String info) {
        if (!enableDisposableFrameKey.equals(key)) {
            return;
        }
        LogUtils.d(TAG, " onFrameAvailable", key, info);
        progressAnimation(true);
    }

    public void setCameraFacing(@Constants.FacingType int facingType) {
        mFacingType = facingType;

        //切换相机需要时间，添加遮罩，防止用户看到上一帧错误画面
        showLoadingView();

        if (mCurCameraUI != null) {
            mCurCameraUI.showAll(false);
        }
        if (mCurCameraWorker != null) {
            mCurCameraWorker.doOnPause();
        }

        if (Constants.FacingType.EXTERIOR == facingType) {
            mCurCameraUI = mCameraDvrUI;
            mCurCameraWorker = mCameraDvrWorker;
        }

        if (mCurCameraUI != null) {
            mCurCameraUI.showAll(true);
        }
        if (mCurCameraWorker != null) {
            mCurCameraWorker.doOnResume();
        }
        updateCameraPreviewFacing();
    }

    private void updateCameraPreviewFacing() {
        if (mCameraPreviewView != null) {
            mCameraPreviewView.setFacing(mFacingType == Constants.FacingType.INTERIOR ? Facing.FRONT : Facing.BACK);
        }
    }

}
